<template>
  <div class="file-upload">
    <el-card>
      <template #header>
        <div class="card-header">
          <span>文件分片上传</span>
        </div>
      </template>

      <el-upload
        ref="uploadRef"
        class="upload-demo"
        drag
        :auto-upload="false"
        :on-change="handleFileChange"
        :show-file-list="false"
      >
        <el-icon class="el-icon--upload">
          <upload-filled />
        </el-icon>
        <div class="el-upload__text">
          将文件拖到此处，或<em>点击上传</em>
        </div>
        <template #tip>
          <div class="el-upload__tip">
            请选择需要上传的文件，支持大文件分片上传
          </div>
        </template>
      </el-upload>

      <div v-if="file" class="file-info">
        <el-descriptions title="文件信息" :column="1" border>
          <el-descriptions-item label="文件名">{{ file.name }}</el-descriptions-item>
          <el-descriptions-item label="文件大小">{{ formatFileSize(file.size) }}</el-descriptions-item>
          <el-descriptions-item label="分片大小">{{ formatFileSize(chunkSize) }}</el-descriptions-item>
          <el-descriptions-item label="分片数量">{{ chunkCount }}</el-descriptions-item>
        </el-descriptions>
      </div>

      <div v-if="uploadProgress > 0" class="upload-progress">
        <el-progress :percentage="uploadProgress" :status="uploadStatus" />
        <div class="progress-text">
          <span>上传进度: {{ uploadedChunks }}/{{ chunkCount }}</span>
          <span v-if="uploadStatus === 'success'">上传完成</span>
          <span v-else-if="uploadStatus === 'exception'">上传失败</span>
        </div>
      </div>

      <div class="upload-actions">
        <el-button 
          type="primary" 
          @click="startUpload" 
          :disabled="!file || uploading"
          :loading="uploading"
        >
          {{ uploading ? '上传中...' : '开始上传' }}
        </el-button>
        <el-button @click="resetUpload" :disabled="uploading">重置</el-button>
      </div>
    </el-card>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'
import { UploadFilled } from '@element-plus/icons-vue'
import { initMultiPartUpload, uploadChunk, mergeChunks, checkChunk } from '@/api/file'

// 引用
const uploadRef = ref()

// 数据状态
const file = ref(null)
const chunkSize = ref(2 * 1024 * 1024) // 2MB per chunk
const chunkCount = ref(0)
const uploading = ref(false)
const uploadProgress = ref(0)
const uploadStatus = ref('')
const uploadedChunks = ref(0)
const fileIdentifier = ref('')

// 处理文件选择变化
const handleFileChange = (fileObj) => {
  file.value = fileObj.raw
  calculateChunks()
}

// 计算分片信息
const calculateChunks = () => {
  if (!file.value) return
  
  chunkCount.value = Math.ceil(file.value.size / chunkSize.value)
  uploadedChunks.value = 0
  uploadProgress.value = 0
  uploadStatus.value = ''
}

// 格式化文件大小
const formatFileSize = (size) => {
  if (size < 1024) {
    return size + ' B'
  } else if (size < 1024 * 1024) {
    return (size / 1024).toFixed(2) + ' KB'
  } else if (size < 1024 * 1024 * 1024) {
    return (size / (1024 * 1024)).toFixed(2) + ' MB'
  } else {
    return (size / (1024 * 1024 * 1024)).toFixed(2) + ' GB'
  }
}

// 开始上传
const startUpload = async () => {
  if (!file.value) {
    ElMessage.warning('请先选择文件')
    return
  }

  uploading.value = true
  uploadStatus.value = ''
  
  try {
    // 1. 初始化分片上传
    const initResponse = await initMultiPartUpload(file.value.name, chunkCount.value)
    if (initResponse.code !== 200) {
      throw new Error(initResponse.message || '初始化上传失败')
    }
    
    fileIdentifier.value = initResponse.data.fileIdentifier
    
    // 2. 逐个上传分片
    uploadedChunks.value = 0
    for (let i = 0; i < chunkCount.value; i++) {
      // 检查分片是否已存在
      const checkResponse = await checkChunk(fileIdentifier.value, i)
      if (checkResponse.code === 200 && checkResponse.data) {
        // 分片已存在，跳过上传
        uploadedChunks.value++
        updateProgress()
        continue
      }
      
      // 计算分片数据
      const start = i * chunkSize.value
      const end = Math.min(file.value.size, start + chunkSize.value)
      const chunk = file.value.slice(start, end)
      
      // 创建FormData
      const formData = new FormData()
      formData.append('file', chunk)
      formData.append('fileIdentifier', fileIdentifier.value)
      formData.append('chunkIndex', i)
      
      // 上传分片
      const uploadResponse = await uploadChunk(formData)
      if (uploadResponse.code !== 200) {
        throw new Error(uploadResponse.message || `上传分片${i}失败`)
      }
      
      uploadedChunks.value++
      updateProgress()
    }
    
    // 3. 合并分片
    const mergeResponse = await mergeChunks(fileIdentifier.value, file.value.name, chunkCount.value)
    if (mergeResponse.code !== 200) {
      throw new Error(mergeResponse.message || '合并文件失败')
    }
    
    // 上传成功
    uploadStatus.value = 'success'
    ElMessage.success('文件上传成功')
  } catch (error) {
    uploadStatus.value = 'exception'
    ElMessage.error('上传失败: ' + error.message)
    console.error('上传失败:', error)
  } finally {
    uploading.value = false
  }
}

// 更新进度
const updateProgress = () => {
  uploadProgress.value = Math.round((uploadedChunks.value / chunkCount.value) * 100)
}

// 重置上传
const resetUpload = () => {
  file.value = null
  chunkCount.value = 0
  uploading.value = false
  uploadProgress.value = 0
  uploadStatus.value = ''
  uploadedChunks.value = 0
  fileIdentifier.value = ''
  uploadRef.value?.clearFiles()
}
</script>

<style scoped>
.file-upload {
  padding: 20px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.file-info {
  margin-top: 20px;
}

.upload-progress {
  margin-top: 20px;
}

.progress-text {
  display: flex;
  justify-content: space-between;
  margin-top: 10px;
  font-size: 14px;
  color: #606266;
}

.upload-actions {
  margin-top: 20px;
  text-align: center;
}

.upload-actions .el-button {
  margin: 0 10px;
}
</style>